package com.laxia.dao.impl;

import com.laxia.dao.BaseDAO;
import com.laxia.mybatis.BaseDomain;
import com.laxia.mybatis.BaseMapper;
import com.laxia.util.CollectionUtil;
import com.laxia.util.NumberUtil;
import tk.mybatis.mapper.entity.Example;

import java.lang.reflect.ParameterizedType;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;


public abstract class BaseDAOImpl<T extends BaseDomain> implements BaseDAO<T> {

    @Override
    public T selectByPrimaryKey(Object key) {
        return mapper().selectByPrimaryKey(key);
    }

    @Override
    public T findValidOne(Long id) {
        if (NumberUtil.isNotPositive(id)) {
            return null;
        }
        try {
            T param = currentEntityClassType().newInstance();
            param.setId(id);
            return mapper().selectOne(param);
        } catch (InstantiationException | IllegalAccessException e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public List<T> findAll() {
        Example example = this.example();
        this.criteria(example);
        return mapper().selectByExample(example);
    }

    @Override
    public List<T> findByIds(Collection<Long> ids) {
        if (CollectionUtil.isEmpty(ids)) {
            return Collections.emptyList();
        }
        Example example = this.example();
        this.criteria(example).andIn("id", ids);
        return mapper().selectByExample(example);
    }

    @Override
    public Map<Long, T> mapByIds(Set<Long> ids) {
        if (CollectionUtil.isEmpty(ids)) {
            return Collections.emptyMap();
        }
        Example example = this.example();
        this.criteria(example).andIn("id", ids);
        List<T> list = mapper().selectByExample(example);
        return list.stream().collect(Collectors.toMap(BaseDomain::getId, Function.identity()));
    }

    @Override
    public List<T> selectByExample(Object example) {
        return mapper().selectByExample(example);
    }

    @Override
    public int insert(T object) {
        return mapper().insert(object);
    }

    @Override
    public int insertSelective(T object) {
        return mapper().insertSelective(object);
    }

    @Override
    public int insertListSelective(List<T> objects) {
        return mapper().insertListSelective(objects);
    }

    @Override
    public int updateByPrimaryKeySelective(T object) {
        return mapper().updateByPrimaryKeySelective(object);
    }


    @Override
    public int save(T object) {
        if (object.getId() != null && object.getId() > 0) {
            return mapper().updateByPrimaryKeySelective(object);
        } else {
            return mapper().insertSelective(object);
        }
    }

    public Example.Criteria criteria(Example example) {
        return example.createCriteria();
    }

    public Example example() {
        return new Example(currentEntityClassType());
    }

    public Example example(Class<T> clazz) {
        return new Example(clazz);
    }

    /**
     * 获取对应的mapper对象
     */
    protected abstract BaseMapper<T> mapper();

    private Class<T> currentEntityClassType() {
        ParameterizedType pType = (ParameterizedType) this.getClass().getGenericSuperclass();
        return (Class<T>) pType.getActualTypeArguments()[0];
    }
}
